package c2.cross.business.ladder.rank;

import c2.cross.business.base.CrossSubModule;
import c2.cross.business.ladder.LadderModule;
import c2.cross.business.ladder.common.LadderOppoDetail;
import cate.common.rpc.path.RpcLadderPath;
import cate.common.table.d.GDLadder;
import cate.game.framework.GameException;
import cate.game.pvp.ladder.common.*;
import cp.solution.rpc.RpcMsgHead;
import cp.solution.util.collection.ListKit;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Collection;
import java.util.List;
import java.util.Optional;

/** 天梯赛排行榜模块 */
@Slf4j
public class LadderRankModule extends CrossSubModule<LadderModule> {

    /** 完整排行榜 */
    @Getter
    private List<LadderOppoDetail> list;

    @Override
    public void initDependent() throws Exception {
        super.initDependent();
        LadderRobotPlaySidePool.init(context);
        this.list = useDb().ladder.getOppoRankList();
        if(ListKit.isEmpty(this.list)) {
            log.info("天梯赛排行榜 从Mongo没有读取到数据, 因此使用机器人初始化列表");
            resetListWithRobots();
            saveRankList();
        } else {
            log.info("天梯赛排行榜 从Mongo读取到{}条数据", this.list.size());
            logSkimList();
        }
        // 监听RPC事件
        useRpcRecv().onRequestResponseTemplate(RpcLadderPath.REFRESH_G2C, LadderRefreshQuery.class, this::refreshHandler);
        useRpcRecv().onRequestResponseTemplate(RpcLadderPath.LOAD_OPPO_PS_G2C, LadderLoadOppoPsQuery.class, this::loadOppoPsHandler);
        useRpcRecv().onRequestResponseTemplate(RpcLadderPath.LOCK_OPPO_G2C, LadderLockOppoQuery.class, this::lockOppoHandler);
        useRpcRecv().onRequestResponseTemplate(RpcLadderPath.REFRESH_RANK_G2C, String.class, this::refreshRankHandler);
        useRpcRecv().onRequestResponseTemplate(RpcLadderPath.UPDATE_RANK_G2C, LadderRankUpdateQuery.class, this::updateRankHandler);
        useRpcRecv().onFireAndForgetTemplate(RpcLadderPath.UPDATE_PS_G2C, LadderPsQuery.class, this::updatePS);
        useRpcRecv().onRequestResponseTemplate(RpcLadderPath.UNLOCK_OPPO_G2C, LadderLockOppoQuery.class, this::unLockOppoHandler);
        useRpcRecv().onRequestResponseTemplate(RpcLadderPath.GET_RANK_LIST, LadderRankListQuery.class, this::getListHandler);
        useRpcRecv().onRequestResponseTemplate(RpcLadderPath.RANK_ADMIRE, LadderRankAdmireQuery.class, this::admireHandler);
    }

    private LadderAdmireResult admireHandler(RpcMsgHead rpcMsgHead, LadderRankAdmireQuery query) {
        return new LadderRankDo().admireRank(this, query);
    }

    private LadderRankListResult getListHandler(RpcMsgHead rpcMsgHead, LadderRankListQuery query) {
        return new LadderRankDo().getRank(this, query);
    }

    private LadderLockOppoResult unLockOppoHandler(RpcMsgHead head, LadderLockOppoQuery query) {
        log.info("收到天梯赛解锁对手的请求 {}", query);
        return new LadderLockOppoDo().unLockExe(context,this,query);
    }

    private <T> void updatePS(RpcMsgHead head, LadderPsQuery query) {
        log.info("收到天梯赛更新防守阵容请求 {}", query);
        new LadderDetailDo().exe(this, query);
    }

    private LadderRankUpdateResult updateRankHandler(RpcMsgHead head, LadderRankUpdateQuery query) {
        log.info("收到天梯赛更新榜单请求 {}", query);
        return new LadderRankDo().updateRank(this, query);
    }

    private LadderLoadOppoPsResult refreshRankHandler(RpcMsgHead head, String query) {
        log.info("收到天梯赛获取个人排名请求 {}", query);
        return new LadderRankDo().getRankById(this, query);
    }

    private LadderRefreshResult refreshHandler(RpcMsgHead head, LadderRefreshQuery query) {
        log.info("收到天梯赛对手数据刷新请求 {}", query);
        return new LadderRefreshDo().exe(context, this, query);
    }

    private LadderLoadOppoPsResult loadOppoPsHandler(RpcMsgHead head, LadderLoadOppoPsQuery query) {
        log.info("收到天梯赛对手阵容拉取的请求 {}", query);
        return new LadderLoadPsDo().exe(this, query);
    }

    private LadderLockOppoResult lockOppoHandler(RpcMsgHead head, LadderLockOppoQuery query) {
        log.info("收到天梯赛锁定对手的请求 {}", query);
        return new LadderLockOppoDo().exe(context,this,query);
    }

    /** 查询对应排名, 返回0代表没有上榜 */
    public int getRankNo(String id) {
        LadderOppoDetail oppo = getOppoDetail(id);
        return oppo != null ? oppo.rank : GDLadder.RANK_NO_NOT_IN_LIST;
    }

    public LadderOppoDetail getOppoDetail(String id) {
        if (StringUtils.isBlank(id)) {
            return null;
        }
        for(LadderOppoDetail oppo : this.list) {
            if(StringUtils.equals(id, oppo.id)) {
                return oppo;
            }
        }
        return null;
    }

    /** 用机器人初始化列表 */
    public synchronized void resetListWithRobots() {
        if(ListKit.isEmpty(this.list)) {
            clearList ();
        }
        for(int i = 0; i < GDLadder.RANK_SIZE; i++) {
            int rankNo = i+1;
            LadderOppoDetail oppo = new LadderOppoDetail();
            // TODO 完善机器人随机名字和形象等信息
            oppo.randomForRobot(rankNo);
            oppo.robotPsId = LadderRobotPlaySidePool.getRobotPsIdByRankNo(rankNo);
            oppo.power = LadderRobotPlaySidePool.getRobotPowerByPsId(oppo.robotPsId);
            oppo.rolePs = LadderRobotPlaySidePool.getRobotPs(oppo.robotPsId);
            oppo.rolePs.snapshot.base.name = oppo.name;
            this.list.add(oppo);
        }
        log.info("使用机器人初始化天梯赛排行榜，结果为:");
        logSkimList();
    }

    /** 排行榜全量入库 */
    public synchronized Collection<LadderOppoDetail> saveRankList() {
        return context.db.ladder.updateOppoRankList(this.list);
    }

    /** 对list进行略读 */
    private void logSkimList() {
        final int SKIM_GAP = 100;
        if(ListKit.isEmpty(this.list)) {
            log.info("天梯赛排行榜 空空如也");
            return;
        }
        log.info("略读间隔{}", SKIM_GAP);
        for(int i = 0; i < this.list.size(); i++) {
            if(i % SKIM_GAP != 0) continue;
            LadderOppoDetail oppo = this.list.get(i);
            log.info("天梯赛排行榜 第{}名 {}", (i+1), oppo);
        }
    }

    public synchronized void updateRank(LadderRankUpdateQuery query) {
        //对方信息
        LadderOppoDetail oppo = getOppoDetail(query.oppoId);
        //个人信息
        LadderOppoDetail self = Optional
                .ofNullable(getOppoDetail(query.selfId))
                .orElse(new LadderOppoDetail());
        //个人信息处理
        self.id = query.selfId;
        self.name = query.name;
        self.rolePs = query.selfPs;
        self.rank = query.selfRank;
        self.srvId = query.srvId;
        self.power = query.power;
        if (query.selfRank > 0) {
            self.rank = query.selfRank;
            list.set(query.selfRank-1, self);
        }
        //对手信息处理
        if (oppo != null) {
            if (query.oppoRank > 0) {
                oppo.rank = query.oppoRank;
                list.set(query.oppoRank-1, oppo);
            }
        }
    }

    @Override
    public void onShutdown() throws Exception {
        super.onShutdown();
        saveRankList();
    }

    public void reset(int srvId,String roleId) throws GameException {
        try {
            useRpcSend().fireAndForgetGameTemplate(RpcLadderPath.RESET_LADDER_C2G,srvId,roleId);
        } catch (Exception e) {
            throw new GameException(e);
        }
    }

    public void clearList () {
        this.list.clear();
    }
}
